Passed
Push — master ( 95c2bf...cd3c12 )
by Rafael S.
02:13
created

index.js ➔ packArray   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
c 0
b 0
f 0
nc 1
nop 3
dl 0
loc 4
rs 10
1
/*!
2
 * byte-data
3
 * Pack and unpack binary data.
4
 * Copyright (c) 2017-2018 Rafael da Silva Rocha.
5
 * https://github.com/rochars/byte-data
6
 *
7
 */
8
9
/** @private */
10
const Type = require("./src/type");
11
/** @private */
12
const endianness = require("endianness");
13
14
/**
15
 * Turn a number or fixed-length string into a byte buffer.
16
 * @param {number|string} value The value.
17
 * @param {Object} type One of the available types.
18
 * @param {number} base The base of the output. Optional. Default is 10.
19
 *      Possible values are 2, 10 or 16.
20
 * @return {!Array<number|string>}
21
 */
22
function pack(value, type, base=10) {
23
    let values = [];
24
    type.base = base;
25
    if (value.constructor == String) {
26
        values = value.slice(0, type.offset);
27
    } else if (!Array.isArray(value)) {
28
        values = [value];
29
    }
30
    return toBytes_(values, type);
31
}
32
33
/**
34
 * Turn a byte buffer into a number or a fixed-length string.
35
 * @param {!Array<number|string>|Uint8Array} buffer An array of bytes.
36
 * @param {Object} type One of the available types.
37
 * @param {number} base The base of the input. Optional. Default is 10.
38
 *      Possible values are 2, 10 or 16.
39
 * @return {number|string}
40
 */
41
function unpack(buffer, type, base=10) {
42
    type.base = base;
43
    let values = fromBytes_(buffer.slice(0, type.offset), type);
44
    if (type.char) {
45
        values = values.slice(0, type.bits / 8);
46
    } else {
47
        values = values[0];
48
    }
49
    return values;
50
}
51
52
/**
53
 * Turn a array of numbers or a string into a byte buffer.
54
 * @param {!Array<number>|string} values The values.
55
 * @param {Object} type One of the available types.
56
 * @param {number} base The base of the output. Optional. Default is 10.
57
 *      Possible values are 2, 10 or 16.
58
 * @return {!Array<number|string>}
59
 */
60
function packArray(values, type, base=10) {
61
    type.base = base;
62
    return toBytes_(values, type);
63
}
64
65
/**
66
 * Turn a byte buffer into a array of numbers or a string.
67
 * @param {!Array<number|string>|Uint8Array} buffer The byte array.
68
 * @param {Object} type One of the available types.
69
 * @param {number} base The base of the input. Optional. Default is 10.
70
 *      Possible values are 2, 10 or 16.
71
 * @return {!Array<number>|string|number}
72
 */
73
function unpackArray(buffer, type, base=10) {
74
    type.base = base;
75
    return fromBytes_(buffer, type);
76
}
77
78
/**
79
 * Turn a struct into a byte buffer.
80
 * A struct is an array of values of not necessarily the same type.
81
 * @param {Array<number|string>} struct The struct values.
82
 * @param {!Array<Object>} def The struct type definition.
83
 * @param {number} base The base of the output. Optional. Default is 10.
84
 *      Possible values are 2, 10 or 16.
85
 * @return {!Array<number|string>}
86
 */
87
function packStruct(struct, def, base=10) {
88
    if (struct.length < def.length) {
89
        return [];
90
    }
91
    let bytes = [];
92
    for (let i = 0; i < def.length; i++) {
93
        bytes = bytes.concat(pack(struct[i], def[i], base));
94
    }
95
    return bytes;
96
}
97
98
/**
99
 * Turn a byte buffer into a struct.
100
 * A struct is an array of values of not necessarily the same type.
101
 * @param {!Array<number|string>|Uint8Array} buffer The byte buffer.
102
 * @param {!Array<Object>} def The struct type definition.
103
 * @param {number} base The base of the input. Optional. Default is 10.
104
 *      Possible values are 2, 10 or 16.
105
 * @return {Array<number|string>}
106
 */
107
function unpackStruct(buffer, def, base=10) {
108
    if (buffer.length < getStructDefSize_(def)) {
109
        return [];
110
    }
111
    let struct = [];
112
    let j = 0;
113
    for (let i=0; i < def.length; i++) {
114
        struct = struct.concat(
115
                unpack(buffer.slice(j, j + def[i].offset), def[i], base)
116
            );
117
        j += def[i].offset;
118
    }
119
    return struct;
120
}
121
122
/**
123
 * Get the length in bytes of a struct definition.
124
 * @param {!Array<Object>} def The struct type definition.
125
 * @return {number} The length of the structure in bytes.
126
 * @private
127
 */
128
function getStructDefSize_(def) {
129
    let bits = 0;
130
    for (let i = 0; i < def.length; i++) {
131
        bits += def[i].offset;
132
    }
133
    return bits;
134
}
135
136
137
/**
138
 * Turn a byte buffer into what the bytes represent.
139
 * @param {!Array<number|string>|Uint8Array} buffer An array of bytes.
140
 * @param {Object} type One of the available types.
141
 * @return {!Array<number>|number|string}
142
 * @private
143
 */
144
function fromBytes_(buffer, type) {
145
    if (type.be) {
146
        endianness(buffer, type.offset);
147
    }
148
    if (type.base != 10) {
149
        bytesFromBase_(buffer, type.base);
150
    }
151
    return readBytes_(buffer, type);
152
}
153
154
/**
155
 * Turn numbers and strings to bytes.
156
 * @param {!Array<number>|number|string} values The data.
157
 * @param {Object} type One of the available types.
158
 * @return {!Array<number|string>} the data as a byte buffer.
159
 * @private
160
 */
161
function toBytes_(values, type) {
162
    let bytes = writeBytes_(values, type);
163
    if (type.be) {
164
        endianness(bytes, type.offset);
165
    }
166
    if (type.base != 10) {
167
        bytesToBase_(bytes, type.base);
168
        formatOutput_(bytes, type);
169
    }
170
    return bytes;
171
}
172
173
/**
174
 * Turn a array of bytes into an array of what the bytes should represent.
175
 * @param {!Array<number>|Uint8Array} bytes An array of bytes.
176
 * @param {Object} type The type.
177
 * @return {!Array<number>|string}
178
 * @private
179
 */
180
function readBytes_(bytes, type) {
181
    let values = [];
182
    let i = 0;
183
    let len = bytes.length - (type.offset - 1);
184
    while (i < len) {
185
        values.push(type.reader(bytes, i));
186
        i += type.offset;
187
    }
188
    if (type.char) {
189
        values = values.join("");
190
    }
191
    return values;
192
}
193
194
/**
195
 * Write values as bytes.
196
 * @param {!Array<number>|number|string} values The data.
197
 * @param {Object} type One of the available types.
198
 * @return {!Array<number>} the bytes.
199
 * @private
200
 */
201
function writeBytes_(values, type) {
202
    let j = 0;
203
    let len = values.length;
204
    let bytes = [];
205
    for(let i=0; i < len; i++) {
206
        j = type.writer(bytes, values[i], j);
207
    }
208
    return bytes;
209
}
210
211
/**
212
 * Turn the output to the correct base.
213
 * @param {Array} bytes The bytes.
214
 * @param {Object} type The type.
215
 * @private
216
 */
217
function formatOutput_(bytes, type) {
218
    let len = bytes.length;
219
    let offset = (type.base == 2 ? 8 : 2) + 1;
220
    for(let i =0; i < len; i++) {
221
        bytes[i] = Array(offset - bytes[i].length).join("0") + bytes[i];
222
    }
223
}
224
225
/**
226
 * Turn bytes to base 10 from base 2 or 16.
227
 * @param {!Array<number>|Uint8Array} bytes The bytes as binary or hex strings.
228
 * @param {number} base The base.
229
 * @private
230
 */
231
function bytesFromBase_(bytes, base) {
232
    let len = bytes.length;
233
    for(let i=0; i < len; i++) {
234
        bytes[i] = parseInt(bytes[i], base);
235
    }
236
}
237
238
/**
239
 * Turn bytes from base 10 to base 2 or 16.
240
 * @param {!Array<string|number>} bytes The bytes.
241
 * @param {number} base The base.
242
 * @private
243
 */
244
function bytesToBase_(bytes, base) {
245
    let len = bytes.length;
246
    for(let i=0; i < len; i++) {
247
        bytes[i] = bytes[i].toString(base);
248
    }
249
}
250
251
// interface
252
module.exports.pack = pack;
253
module.exports.unpack = unpack;
254
module.exports.packArray = packArray;
255
module.exports.unpackArray = unpackArray;
256
module.exports.unpackStruct = unpackStruct;
257
module.exports.packStruct = packStruct;
258
module.exports.Type = Type;
259
/** 
260
 * A char.
261
 * @type {Object}
262
 */
263
module.exports.chr = new Type({"bits": 8, "char": true});
264
/**
265
 * A 4-char string
266
 * @type {Object}
267
 */
268
module.exports.fourCC = new Type({"bits": 32, "char": true});
269
/**
270
 * Booleans
271
 * @type {Object}
272
 */
273
module.exports.bool = new Type({"bits": 1});
274
/**
275
 * Signed 2-bit integers
276
 * @type {Object}
277
 */
278
module.exports.int2 = new Type({"bits": 2, "signed": true});
279
/**
280
 * Unsigned 2-bit integers
281
 * @type {Object}
282
 */
283
module.exports.uInt2 = new Type({"bits": 2});
284
/**
285
 * Signed 4-bit integers
286
 * @type {Object}
287
 */
288
module.exports.int4 = new Type({"bits": 4, "signed": true});
289
/**
290
 * Unsigned 4-bit integers
291
 * @type {Object}
292
 */
293
module.exports.uInt4 = new Type({"bits": 4});
294
/**
295
 * Signed 8-bit integers
296
 * @type {Object}
297
 */
298
module.exports.int8 = new Type({"bits": 8, "signed": true});
299
/**
300
 * Unsigned 4-bit integers
301
 * @type {Object}
302
 */
303
module.exports.uInt8 = new Type({"bits": 8});
304
// LE
305
/**
306
 * Signed 16-bit integers little-endian
307
 * @type {Object}
308
 */
309
module.exports.int16  = new Type({"bits": 16, "signed": true});
310
/**
311
 * Unsigned 16-bit integers little-endian
312
 * @type {Object}
313
 */
314
module.exports.uInt16 = new Type({"bits": 16});
315
/**
316
 * Half-precision floating-point numbers little-endian
317
 * @type {Object}
318
 */
319
module.exports.float16 = new Type({"bits": 16, "float": true});
320
/**
321
 * Signed 24-bit integers little-endian
322
 * @type {Object}
323
 */
324
module.exports.int24 = new Type({"bits": 24, "signed": true});
325
/**
326
 * Unsigned 24-bit integers little-endian
327
 * @type {Object}
328
 */
329
module.exports.uInt24 = new Type({"bits": 24});
330
/**
331
 * Signed 32-bit integers little-endian
332
 * @type {Object}
333
 */
334
module.exports.int32 = new Type({"bits": 32, "signed": true});
335
/**
336
 * Unsigned 32-bit integers little-endian
337
 * @type {Object}
338
 */
339
module.exports.uInt32 = new Type({"bits": 32});
340
/**
341
 * Single-precision floating-point numbers little-endian
342
 * @type {Object}
343
 */
344
module.exports.float32 = new Type({"bits": 32, "float": true});
345
/**
346
 * Signed 40-bit integers little-endian
347
 * @type {Object}
348
 */
349
module.exports.int40 = new Type({"bits": 40, "signed": true});
350
/**
351
 * Unsigned 40-bit integers little-endian
352
 * @type {Object}
353
 */
354
module.exports.uInt40 = new Type({"bits": 40});
355
/**
356
 * Signed 48-bit integers little-endian
357
 * @type {Object}
358
 */
359
module.exports.int48 = new Type({"bits": 48, "signed": true});
360
/**
361
 * Unsigned 48-bit integers little-endian
362
 * @type {Object}
363
 */
364
module.exports.uInt48 = new Type({"bits": 48});
365
/**
366
 * Double-precision floating-point numbers little-endian
367
 * @type {Object}
368
 */
369
module.exports.float64 = new Type({"bits": 64, "float": true});
370
// BE
371
/**
372
 * Signed 16-bit integers big-endian
373
 * @type {Object}
374
 */
375
module.exports.int16BE  = new Type({"bits": 16, "signed": true, "be": true});
376
/**
377
 * Unsigned 16-bit integers big-endian
378
 * @type {Object}
379
 */
380
module.exports.uInt16BE = new Type({"bits": 16, "be": true});
381
/**
382
 * Half-precision floating-point numbers big-endian
383
 * @type {Object}
384
 */
385
module.exports.float16BE = new Type({"bits": 16, "float": true, "be": true});
386
/**
387
 * Signed 24-bit integers big-endian
388
 * @type {Object}
389
 */
390
module.exports.int24BE = new Type({"bits": 24, "signed": true, "be": true});
391
/**
392
 * Unsigned 24-bit integers big-endian
393
 * @type {Object}
394
 */
395
module.exports.uInt24BE = new Type({"bits": 24, "be": true});
396
/**
397
 * Signed 32-bit integers big-endian
398
 * @type {Object}
399
 */
400
module.exports.int32BE = new Type({"bits": 32, "signed": true, "be": true});
401
/**
402
 * Unsigned 32-bit integers big-endian
403
 * @type {Object}
404
 */
405
module.exports.uInt32BE = new Type({"bits": 32, "be": true});
406
/**
407
 * Single-precision floating-point numbers big-endian
408
 * @type {Object}
409
 */
410
module.exports.float32BE = new Type({"bits": 32, "float": true, "be": true});
411
/**
412
 * Signed 40-bit integers big-endian
413
 * @type {Object}
414
 */
415
module.exports.int40BE = new Type({"bits": 40, "signed": true, "be": true});
416
/**
417
 * Unsigned 40-bit integers big-endian
418
 * @type {Object}
419
 */
420
module.exports.uInt40BE = new Type({"bits": 40, "be": true});
421
/**
422
 * Signed 48-bit integers big-endian
423
 * @type {Object}
424
 */
425
module.exports.int48BE = new Type({"bits": 48, "signed": true, "be": true});
426
/**
427
 * Unsigned 48-bit integers big-endian
428
 * @type {Object}
429
 */
430
module.exports.uInt48BE = new Type({"bits": 48, "be": true});
431
/**
432
 * Double-precision floating-point numbers big-endian
433
 * @type {Object}
434
 */
435
module.exports.float64BE = new Type({"bits": 64, "float": true, "be": true});
436